require "base_def"

local hand_socket_connect = {}

--============================= Socket start =============================--
local SOCKET = {}
local gate 

--message
local function DispatchMsg(fd, msg, len)
	--苹果手机断线会走这里len==2
    if not len or (len <= 2) then                
        log.info('dispatch_msg, msg len is', len, 'maybe close, fd:', fd)
        --skynet.send('.hall_msg', 'lua', 'passive_quit', fd)
        return
    end

	--转给wg服务处理消息分发
	local msgData = skynet.tostring(msg, len)
	SendWg(fd, msgData)
end

function SOCKET.open(session, fd, addr, connType)
	log.info("New client from : " .. addr, " session: "..session.." gate: "..gate)
	--[[
	--不再用默认agent是一个服务的方式，而改用直接table管理省去了不必要的生成和销毁
	agent[fd] = skynet.newservice("agent")
	skynet.call(agent[fd], "lua", "start", { gate = gate, client = fd, watchdog = skynet.self() })
	--]]

	--wsgate监听
	skynet.call(session, "lua", "forward", fd)

	--
	hand_socket_connect.AgentOpen(fd, addr, connType)
end

function SOCKET.close(session, fd)
	log.info("socket close: ",fd)
	hand_socket_connect.AgentClose(fd)
end

function SOCKET.error(session, fd, msg)
	log.error("SOCKET error session=", session)
	log.error("SOCKET error fd=", fd)
	log.error("SOCKET error msg=", msg)
	hand_socket_connect.AgentClose(fd)
end

function SOCKET.warning(session, fd, size)
	-- size K bytes havn't send out in fd
	log.warning("SOCKET warning session=", session)
	log.warning("SOCKET warning fd=", fd)
	log.warning("SOCKET warning msg=", size)
end

function SOCKET.data(session, fd, msg)
	log.info("SOCKET data session=", session)
	log.info("SOCKET data fd=", fd)
	log.info("SOCKET data msg=", msg)
end

--=========================== hand_socket_connect start ===========================--
function hand_socket_connect.start(conf)
	log.info("hand_socket_connect.start conf=", conf)
	skynet.call(gate, "lua", "open" , conf)
end

function hand_socket_connect.close(fd)
	hand_socket_connect.AgentClose(fd)
end

function hand_socket_connect.socket(session, cmd, fd, ...)
    local f = SOCKET[cmd]
    if f then
        f(session, fd, ...)
    end
end

skynet.start(function()
    skynet.register_protocol {
        name = "client",
        id = skynet.PTYPE_CLIENT,
        unpack = function(msgbuf, msgsize) return msgbuf, msgsize end,
        dispatch = function(fd, address, msg, len)
            assert(fd, 'fd is error', fd)
            skynet.ignoreret()		-- session is fd, don't call skynet.ret
			--log.info("client DispatchMsg msg=", msg)
			DispatchMsg(fd, msg, len)
        end
    }

	skynet.dispatch("lua", function(_, session, cmd, ...)
		log.info("client hand_socket_connect cmd=", cmd)
        local f = hand_socket_connect[cmd]
        if not f then
            assert(f, "hall_service 接收到非法lua消息: "..cmd)
            return
        end
        if cmd == 'socket' then
            skynet.retpack(f(session, ...))
        else
            if session > 0 then
                skynet.ret(skynet.pack(f(...)))
            else
                f(...)
            end
        end
	end)

	--
	skynet.register(".hand_socket_connect")
	--websocket网关
	gate = skynet.newservice("wsgate")
	--[[
	--socket网关
	gate = skynet.newservice("gate")
	--]]
	--init
	hand_socket_connect.Init()
end)

--检测超时的掉线，清除其登录信息
local function check_agent_close()
    while true do
        skynet.sleep(hand_socket_connect.reconTime)
        for userId, agent in pairs(hand_socket_connect.discntAgent) do
            if os.time() - agent.last_beat_time > hand_socket_connect.reconTime then
                hand_socket_connect.discntAgent[userId] = nil
                log.info("check_agent_close heat_beat_offline: ",userId)
            end
        end
    end
end

--init
function hand_socket_connect.Init()
	--重连恢复时间: 2分钟
	hand_socket_connect.reconTime = 4 * 100 * 0.5
	--当前连接中的agent表
    hand_socket_connect.agent = {}
    --当前处于掉线的agent表
    hand_socket_connect.discntAgent = {}
    --fork一个定时器，x秒执行，将掉线表内大于x秒的agent断开(即登录信息过期)
	skynet.fork(check_agent_close)
end

--agent打开
function hand_socket_connect.AgentOpen(fd, addr, connType)
	--记录connect_agent的数据
	local theAgent = {}
	theAgent.fd = fd
	theAgent.addr = addr
	theAgent.connType = connType
	hand_socket_connect.agent[fd] = theAgent
	log.info("agent=", hand_socket_connect.agent)
end

--agent关闭
function hand_socket_connect.AgentClose(fd)
	log.info("hand_socket_connect.AgentClose fd: ", fd)
	local theAgent = hand_socket_connect.agent[fd]
	if theAgent then
		skynet.call(gate, "lua", "kick", fd)
		-- disconnect never return
		--不用skynet推荐的agent模式，省去了服务的频繁启动销毁，直接用内存记录agent数据即可
		-- skynet.send(a, "lua", "disconnect")
		hand_socket_connect.agent[fd] = nil
	end
end

--登录成功后的客户端断线
function hand_socket_connect.AgentDisconnect(userId)
    local agent = TableCopy(hand_socket_connect.agent[userId])
    if agent then
        agent.last_beat_time = os.time()
        self.discntAgent[userId] = agent
        self.agent[userId] = nil
        log.info("AgentDisconnect agent=", agent)
    else 
        log.error("hand_agent_info:AgentDisconnect error userId=", userId)
    end
end

function hand_socket_connect.GetAgentConnectInfo(fd)
	local theAgent = hand_socket_connect.agent[fd]
	if theAgent then 
		return true, theAgent
	else
		log.error("GetAgentConnectInfo get theAgent error fd=", fd)
	end
end

--